/* tslint:disable */
import { map, catchError, mergeMap } from 'rxjs/operators'
import { of } from 'rxjs/observable/of';
import { concat } from 'rxjs/observable/concat';
import { Injectable, Inject } from '@angular/core';
import { Effect, Actions } from '@ngrx/effects';

import { LoopbackAction } from '../models/BaseModels';
import { BaseLoopbackEffects } from './base';
import { resolver } from './resolver';

import * as actions from '../actions';
import { <%- modelName %>ActionTypes, <%- modelName %>Actions } from '../actions/<%- modelName %>';
import { LoopbackErrorActions } from '../actions/error';
import { <%- modelName %>Api } from '../services/index';

@Injectable()
export class <%- modelName %>Effects extends BaseLoopbackEffects {
<% model.methods.forEach(function(action) {
  var methodName = action.name.split('.').join('$').replace('prototype$', '').replace(/::/g, '__');

  // all of these methods are extended from base service
  if (methodName.match(/(^create$|^createMany$|^find$|^replaceOrCreate$|^replaceById$|^upsert$|^upsertWithWhere$|^exists$|^findOne$|^findById$|^deleteById$|^updateAttributes$|^patchOrCreate$|^patchAttributes$|^updateAll$|^count$|^createChangeStream$)/)) { return; }

  // Unsupported and out of scope methods
  if (methodName.match(/(^exists$|^__exists|^myRemote$|^stats$|^count$|^__count)/)) { return; }

  if (!model.sharedClass.ctor.settings.sdk.blacklist[methodName]) {
-%>
  @Effect()
  public <%- normalizeMethodName(methodName) %>$ = this.actions$
    .ofType(<%- modelName %>ActionTypes.<%- upperCasedMethodName(methodName) %>).pipe(
      mergeMap((action: LoopbackAction) =>
        this.<%- modelName.toLowerCase() %>.<%- normalizeMethodName(methodName) %>(<%- buildMethodParamsFromPayload(model, methodName, action.accepts) %>).pipe(
      <% if (methodName.match(/(^__delete)/)) { -%>
    map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload, action.meta)),
      <% } else if (methodName.match(/(^logout$)/)) { -%>
    map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.meta)),
      <% } else if (methodName.match(/(^login$)/)) { -%>
    map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(response, action.meta)),
      <% } else if (methodName.match(/(^__findById|^__updateById)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
            resolver({id: action.payload.id, data: response, meta: action.meta}, '<%- model.sharedClass.ctor.relations[rel].targetClass %>', 'findByIdSuccess'),
            of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
          )),
      <% } else if (methodName.match(/(^__update)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
            resolver({data: [response], meta: action.meta}, '<%- model.sharedClass.ctor.relations[rel].targetClass %>', 'findSuccess'),
            of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
          )),
      <% } else if (methodName.match(/(^__get|^__create)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
            resolver({data: response, meta: action.meta}, '<%- model.sharedClass.ctor.relations[rel].targetClass %>', 'findSuccess'),
            of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
          )),
      <% } else if (methodName.match(/(^__destroyById)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
            resolver({data: response, meta: action.meta}, '<%- model.sharedClass.ctor.relations[rel].targetClass %>', 'deleteByIdSuccess'),
            of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
          )),
      <% } else if (methodName.match(/(^__link)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
          of(new actions['<%- capitalize(model.sharedClass.ctor.relations[rel].modelThrough.definition.name) %>Actions'].createSuccess(response, action.meta)),
          of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
        )),
      <% } else if (methodName.match(/(^__unlink)/) && model.sharedClass.ctor.relations[action.name.split('__').pop()].targetClass) {
        var rel = action.name.split('__').pop(); -%>
    mergeMap((response: any) => concat(
          of(new actions['<%- capitalize(model.sharedClass.ctor.relations[rel].modelThrough.definition.name) %>Actions'].deleteByIdSuccess(response.id, action.meta)),
          of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta))
        )),
      <% } else if (!action.returns || action.returns.length == 0) { -%>
    map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, action.payload.fk, action.meta)),
      <% } else { -%>
    map((response: any) => new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Success(action.payload.id, response, action.meta)),
      <% } -%>
    catchError((error: any) => concat(
            of(new <%- modelName %>Actions.<%- normalizeMethodName(methodName) %>Fail(error, action.meta)),
            of(new LoopbackErrorActions.error(error, action.meta))
          ))
        )
      )
    );

<% } -%>
<% }); // model.methods.foreach -%>
  <% if (model.isUser) { -%>
  /**
   * @author João Ribeiro <@JonnyBGod> <github:JonnyBGod>
   * @description
   * <%- modelName %> specific actions
   */
  @Effect()
  public signup$ = this.actions$
    .ofType(<%- modelName %>ActionTypes.SIGNUP).pipe(
      mergeMap((action: LoopbackAction) =>
        this.<%- modelName.toLowerCase() %>.create(action.payload).pipe(
          map((response: any) => new <%- modelName %>Actions.signupSuccess(action.payload, response, action.meta)),
          catchError((error: any) => concat(
            of(new <%- modelName %>Actions.signupFail(error, action.meta)),
            of(new LoopbackErrorActions.error(error, action.meta))
          ))
        )
      )
    );

  <% } -%>
  /**
   * @author João Ribeiro <@JonnyBGod> <github:JonnyBGod>
   * @description
   * Decorate base effects metadata
   */
  @Effect() public create$;
  @Effect() public createMany$;
  @Effect() public findById$;
  @Effect() public find$;
  @Effect() public findOne$;
  @Effect() public updateAll$;
  @Effect() public deleteById$;
  @Effect() public updateAttributes$;
  @Effect() public upsert$;
  @Effect() public upsertWithWhere$;
  @Effect() public replaceOrCreate$;
  @Effect() public replaceById$;
  @Effect() public patchOrCreate$;
  @Effect() public patchAttributes$;

  constructor(
    @Inject(Actions) public actions$: Actions,
    @Inject(<%- modelName %>Api) public <%- modelName.toLowerCase() %>: <%- modelName %>Api
  ) {
    super(actions$, <%- modelName.toLowerCase() %>, '<%- modelName %>', <%- modelName %>ActionTypes, <%- modelName %>Actions);
  }
}
